#
# TOOL-CHAIN
#
CC := g++
LD := ld
OC := objcopy

# INSTALL-GRUB2
name := "RPI OS"
GRUB2SCRIPTPATH = $(grub2-directory)/90_rpi_os
GRUB2SCRIPT_HDNUM := `basename $(destination-partition-file) | tr -d [:digit:] | tail --bytes=2 | tr '[a-z]' '[0-9]'`
GRUB2SCRIPT_DEVICEINDEX := `basename $(destination-partition-file) | tr -d [:alpha:]`
DESTINATION_PARTITION_SECTOR := 0
DESTINATION_PARTITION_DEVICE := $(shell echo $(destination-partition-file) | tr -d [:digit:])

ifeq (1, $(words $(findstring $(MAKECMDGOALS), install-grub2)))
  $(shell touch src/mbrboot.S)
  DESTINATION_PARTITION_SECTOR := $(shell sudo fdisk -u -l $(DESTINATION_PARTITION_DEVICE) | grep $(destination-partition-file) | cut -c 15-26 | tr -d [:space:])
endif

ifneq ($(wildcard obj/__grub__),) 
  $(shell touch src/mbrboot.S)
  $(shell rm obj/__grub__)
endif

# COMPILE/LINK FLAGS
CFLAGS := -I src -std=c++0x -g -O0 -nostdinc -Wall -static -fno-common -fno-exceptions -fno-stack-protector -fno-non-call-exceptions -fno-weak -fno-builtin -ffreestanding -nostdlib -mno-red-zone -mno-mmx -mno-sse -mno-sse2 -mno-sse3 -mno-3dnow -fno-rtti -m32 -mtune=i386 -D ARCH=ARCH_X86_32 -D __RPI_OS_PARTITION_START_SECTOR__=$(DESTINATION_PARTITION_SECTOR) -c
LFLAGS := -nostdlib -nodefaultlibs -melf_i386 -g

#
# SOURCES
#
CPPSRCFILES := $(shell find src -type f -name "*.cpp") $(shell find src -type f -name "*.cxx")
ASMSRCFILES := $(shell find src -type f -name "*.S")
HDRFILES := $(shell find src -type f -name "*.h") $(shell find src -type f -name "*.hpp")
SRCFILES := $(CPPSRCFILES) $(ASMSRCFILES)

DEPFILES := $(patsubst src/%,obj/%,$(patsubst %,%.d,$(SRCFILES)))
OBJFILES := $(patsubst src/%,obj/%,$(patsubst %,%.o,$(SRCFILES)))

OBJFILES := $(filter-out obj/mbrboot.S.o,$(OBJFILES))
OBJFILES := $(filter-out obj/boot.S.o,$(OBJFILES))
OBJFILES := $(filter-out obj/realthunk.S.o,$(OBJFILES))
OBJFILES := $(filter-out obj/kernelentry.cpp.o,$(OBJFILES))
OBJFILES := obj/kernelentry.cpp.o $(OBJFILES)

#
# MAIN TARGET
#
bin/disk.img: utils/diskmbr/diskmbr obj/kernel obj/mbrboot
	if [ ! -f $@ ]; then dd if=/dev/zero of=$@ oflag=append count=409600 conv=notrunc,sync > /dev/null 2>&1 ; fi
	utils/diskmbr/diskmbr -create obj/mbrboot > obj/mbr
	dd if=obj/mbr of=$@ seek=0 count=1 conv=notrunc,sync > /dev/null 2>&1
	dd if=obj/boot of=$@ seek=1 count=1 conv=notrunc,sync > /dev/null 2>&1
	dd if=obj/realthunk of=$@ seek=2 count=1 conv=notrunc,sync > /dev/null 2>&1
	dd if=obj/kernel of=$@ seek=3 conv=notrunc,sync > /dev/null 2>&1

NODEPS:=clean
#Don't create dependencies when we're cleaning
ifeq (0, $(words $(findstring $(MAKECMDGOALS), $(NODEPS))))
  -include $(DEPFILES)
endif

#
# DEPENDS FILES
#
.PRECIOUS : obj/%.d
obj/%.d: src/%
	$(CC) $(CFLAGS) -MP -MM -MT '$(patsubst src/%,obj/%,$(patsubst %,%.o,$<))' $< > $@

.PRECIOUS : obj/mbrboot.S.d
obj/mbrboot.S.d: src/mbrboot.S
	$(CC) $(CFLAGS) -D __RPI_OS_PARTITION_START_SECTOR__=$(DESTINATION_PARTITION_SECTOR) -D KERNEL_NUM_SECTORS=1 -D BOOT_NUM_SECTORS=1 -D REALTHUNK_NUM_SECTORS=1 -MP -MM -MT '$(patsubst src/%,obj/%,$(patsubst %,%.o,$<))' $< > $@

#
# OBJECT FILES
#
obj/%.o: src/% obj/%.d Makefile
	$(CC) $(CFLAGS) $< -o $@

obj/mbrboot.S.o: obj/kernel obj/boot obj/realthunk src/mbrboot.S Makefile
	$(CC) $(CFLAGS) -D __RPI_OS_PARTITION_START_SECTOR__=$(DESTINATION_PARTITION_SECTOR) -D KERNEL_NUM_SECTORS=`du --apparent-size --block-size=512 obj/kernel | cut -f 1` -D BOOT_NUM_SECTORS=`du --apparent-size --block-size=512 obj/boot | cut -f 1` -D REALTHUNK_NUM_SECTORS=`du --apparent-size --block-size=512 obj/realthunk | cut -f 1` src/mbrboot.S -o obj/mbrboot.S.o

#
# CODE FILES
#
obj/kernel: $(OBJFILES)
	$(LD) $(LFLAGS) -T src/kernel.ld -o obj/kernel.out $(OBJFILES) -b binary
	$(OC) -S -O binary obj/kernel.out obj/kernel

obj/mbrboot: obj/mbrboot.S.o
	$(LD) $(LFLAGS) -N -e MBRBoot -Ttext 0x7C00 -o obj/mbrboot.S.out obj/mbrboot.S.o
	$(OC) -S -O binary obj/mbrboot.S.out obj/mbrboot

obj/boot: obj/boot.S.o
	$(LD) $(LFLAGS) -N -e Boot -Ttext 0x8000 -o obj/boot.S.out obj/boot.S.o
	$(OC) -S -O binary obj/boot.S.out obj/boot

obj/realthunk: obj/realthunk.S.o
	$(LD) $(LFLAGS) -N -e RealThunk -Ttext 0x8400 -o obj/realthunk.S.out obj/realthunk.S.o
	$(OC) -S -O binary obj/realthunk.S.out obj/realthunk

#
# COMMANDS
#
.PHONY : debug-gdb
debug-gdb: bin/disk.img
	qemu -bios utils/qemu-0.12.5/pc-bios/bios.bin -vga std -k en-us -hda bin/disk.img -serial stdio -s -S

.PHONY : debug-ddd
debug-ddd: bin/disk.img
	ddd &
	qemu -bios utils/qemu-0.12.5/pc-bios/bios.bin -vga std -k en-us -hda bin/disk.img -serial stdio -s -S

.PHONY : debug
debug: debug-gdb

.PHONY : run
run: bin/disk.img
	qemu -bios utils/qemu-0.12.5/pc-bios/bios.bin -vga std -k en-us -hda bin/disk.img -serial stdio

.PHONY : clean
clean:
	rm -f obj/* bin/*
	rm -f utils/diskmbr/diskmbr

.PHONY : install-grub2
install-grub2: bin/disk.img
	@echo Installing os...
	@# Check arguments
	@if [ -z $(grub2-directory) ]; then echo "ERROR: grub2-directory not specified" ; false ; \
	else \
	if [ ! -d $(grub2-directory) ]; then echo "ERROR: grub2-directory does not exist" ; false ; \
	fi ; \
	fi
	@if [ -z $(destination-partition-file) ]; then echo "ERROR: destination-partition-file not specified" ; false; \
	else \
	if sudo [ ! -b $(destination-partition-file) ]; then echo "ERROR: destination-partition-file does not exist" ; false; \
	fi ; \
	fi
	@# Install
	@echo Copying os disk image to $(destination-partition-file)...
	sudo dd if=bin/disk.img of=$(destination-partition-file)
	sudo sh -c "echo exec\ tail\ --lines=4\ '$$''0' > $(GRUB2SCRIPTPATH)"
	sudo sh -c "echo menuentry \"'`echo \"$(name)\" | sed -e 's/\(\/\|\\\|&\)/\\&/g'`'\" { >> $(GRUB2SCRIPTPATH)"
	sudo sh -c "echo \"set root=(hd$(GRUB2SCRIPT_HDNUM),$(GRUB2SCRIPT_DEVICEINDEX))\" >> $(GRUB2SCRIPTPATH)"
	sudo sh -c "echo \"chainloader +1\" >> $(GRUB2SCRIPTPATH)"
	sudo sh -c "echo \"}\" >> $(GRUB2SCRIPTPATH)"
	sudo chmod +x $(GRUB2SCRIPTPATH)
	@echo "Updating grub2..."
	@sudo update-grub
	@touch obj/__grub__

include utils/diskmbr/Makefrag
